<HTML>
<HEAD>
   <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
   <TITLE>Chapter 10:	 scalcout - String Calculation Output Record</TITLE>

</HEAD>
<BODY>

<H1>
scalcout - String Calculation Output Record</H1>

<!-- TOC -->
<H2>Contents</H2>
<DL>
<DT><A HREF="#HEADING14-1"><B>1. </B>- Introduction</A></DT>

<DT><A HREF="#HEADING14-11"><B>2. </B>- Scan Parameters</A></DT>

<DT><A HREF="#HEADING14-13"><B>3. </B>- Read Parameters</A></DT>

<DT><A HREF="#HEADING14-16"><B>4. </B>- Expressions</A></DT>

<DT><A HREF="#HEADING14-19"><B>4.1. </B>- Operands</A></DT>

<DT><A HREF="#HEADING14-21"><B>4.2. </B>- Algebraic Functions/Operators</A></DT>

<DT><A HREF="#HEADING14-39"><B>4.3. </B>- Trigonometric Functions</A></DT>

<DT><A HREF="#HEADING14-49"><B>4.4. </B>- Relational Operators</A></DT>

<DT><A HREF="#HEADING14-56"><B>4.5. </B>- Logical Operators</A></DT>

<DT><A HREF="#HEADING14-60"><B>4.6. </B>- Bitwise Operators</A></DT>

<DT><A HREF="#HEADING14-69"><B>4.7. </B>- Special Characters</A></DT>

<DT><A HREF="#HEADING14-72"><B>4.8. </B>- Conditional Expression</A></DT>

<DT><A HREF="#HEADING14-73"><B>4.9. </B>- String Functions/Operators</A></DT>

<DT><A HREF="#HEADING14-74"><B>4.10. </B>- Array Operators</A></DT>

<DT><A HREF="#HEADING14-75"><B>4.11. </B>- Miscellaneous Operators</A></DT>

<DT><A HREF="#HEADING14-76"><B>4.12. </B>- Examples</A></DT>

<DT><A HREF="#HEADING14-77">Algebraic</A></DT>

<DT><A HREF="#HEADING14-79">Relational</A></DT>

<DT><A HREF="#HEADING14-83">Question Mark</A></DT>

<DT><A HREF="#HEADING14-91">Logical</A></DT>

<DT><A HREF="#HEADING14-92">String</A></DT>

<DT><A HREF="#HEADING14-93">Argument Array</A></DT>

<DT><A HREF="#HEADING14-94">Store</A></DT>

<DT><A HREF="#HEADING14-95">Loop</A></DT>

<DT><A HREF="#HEADING14-98"><B>5. </B>- Output Parameters</A></DT>

<DT><A HREF="#HEADING14-109"><B>6. </B>- Operator Display Parameters</A></DT>

<DT><A HREF="#HEADING14-122"><B>7. </B>- Alarm Parameters</A></DT>

<DT><A HREF="#HEADING14-126"><B>8. </B>- Monitor Parameters</A></DT>

<DT><A HREF="#HEADING14-128"><B>9. </B>- Run-time Parameters</A></DT>

<DT><A HREF="#HEADING14-132"><B>10. </B>- Record Support Routines</A></DT>

<DT><A HREF="#HEADING14-133">init_record</A></DT>

<DT><A HREF="#HEADING14-136">process</A></DT>

<DT><A HREF="#HEADING14-138">special</A></DT>

<DT><A HREF="#HEADING14-140">get_value</A></DT>

<DT><A HREF="#HEADING14-142">get_units</A></DT>

<DT><A HREF="#HEADING14-144">get_precision</A></DT>

<DT><A HREF="#HEADING14-146">get_graphic_double</A></DT>

<DT><A HREF="#HEADING14-148">get_control_double</A></DT>

<DT><A HREF="#HEADING14-150">get_alarm_double</A></DT>

<DT><A HREF="#HEADING14-156"><B>11. </B>- Record Processing</A></DT>

<DT><A HREF="#HEADING14-157"><B>11.1. </B>- process()</A></DT>

<DT><A HREF="#HEADING14-169"><B>11.2. </B>- execOutput()</A></DT>

<DT><A HREF="#HEADING14-170"><B>12. </B>- Sample Database</A></DT>

</DL>


<HR><A NAME="HEADING14-1"></A>
<H1>
1. Introduction</H1>

The String Calculation Output or "scalcout" record is derived from the Calcout
record in EPICS base, and extends it by supporting string expressions in
addition to numeric expressions.&nbsp; The record has 12 string fields (AA...LL)
and 12 double fields (A...L) which are used as input variables for the
expression.  It calls an extended version of the EPICS calculation engine that
accepts string arguments, supports a variety of string functions, and produces a
string result and a numeric result.

<P>If the expression involves any string operators or operands, the calc engine
produces a string result, and converts it to double, using atof(); otherwise, it
produces a numeric result and converts it to string, using cvtDoubleToString()
from EPICS base.

<P>When writing to a string PV (any of DBF_STRING, DBF_ENUM, DBF_MENU,
DBF_DEVICE, DBF_INLINK, DBF_OUTLINK, DBF_FWDLINK) the record (actually, device
support) writes its string value (SVAL or OSV).  When writing to any other kind
of PV, the record writes its numeric value (VAL or OVAL).

<P>To write successfully to a DBF_MENU or DBF_ENUM (for example, the VAL field
of a <code>bo</code> or <code>mbbo</code> record) the record's string value must
be one of the possible strings for the PV, or it must an integer specifying the
string number [0..N] for the PV.  For example, when writing to a <code>bo</code>
record whose ZNAM is "No" and whose ONAM is "Yes", the string value must be one
of the following: "No", "Yes", "0", and "1".  To ensure that numeric values are
converted to integers, set the precision (the PREC field) to zero.

<P>&nbsp;
<HR><A NAME="HEADING14-11"></A>
<H1>
2. Scan Parameters</H1>

The scalcout record has the standard fields for specifying under what
circumstances the record will be processed.  See the EPICS Record Reference
Manual for these fields and their use.

<P>&nbsp;
<HR><A NAME="HEADING14-13"></A>

<H1>
3. Read Parameters</H1>

The read parameters for the scalcout record consist of 24 input links:
12 to numeric fields (INPA -> A, INPB -> B, . . . INPL -> L); and 12 to
string fields (INAA -> AA, INBB -> BB, ...INLL -> LL). The fields can be
database links, channel access links, or constants. If they are links,
they must specify another record's field. If they are constants, they will
be initialized with the value they are configured with and can be changed
via <TT>dbPuts</TT>. These fields cannot be hardware addresses. In addition,
the scalcout record contains the fields INAV, INBV, . . . INLV, which indicate
the status of the links to numeric fields, and the fields IAAV, IBBV, .
. . ILLV, which indicate the status of the links to string fields.&nbsp;
These fields indicate whether or not the specified PV was found and a link
to it established. See <A HREF="#MARKER-9-2">Section 6, <I>Operator Display
Parameters</I></A> for an explanation of these fields.

<P>From most types of PV's, the scalcout record's string input links fetch data
as strings, and depend on EPICS to convert a PV's native value to string.  But
when an scalcout record's string input link names a PV whose data type is an
array of DBF_CHAR or DBF_UCHAR, the record fetches up to 39 array elements from
the array in their native form, translates the result using
epicsStrSnPrintEscaped(), strips any trailing "\000" string fragments, and
truncates the result to fit into a 40-character string.

<P>&nbsp;See the EPICS Record Reference Manual for information on how to specify database links.
<TABLE BORDER NOSAVE >
<TR>
<TH>Field</TH>
<TH>Summary</TH>
<TH>Type</TH>
<TH>DCT</TH>
<TH>Initial</TH>
<TH>Access</TH>
<TH>Modify</TH>
<TH>Rec Proc Monitor</TH>
</TR>

<TR NOSAVE>
<TD NOSAVE>INPA</TD>
<TD>Input Link A</TD>
<TD>INLINK</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>N/A</TD>
</TR>

<TR>
<TD>INPB</TD>
<TD>Input Link B</TD>
<TD>INLINK</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>N/A</TD>
</TR>

<TR>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
</TR>

<TR>
<TD>INPL</TD>
<TD>Input Link L</TD>
<TD>INLINK</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>N/A</TD>
</TR>

<TR>
<TD>INAA</TD>
<TD>Input Link AA</TD>
<TD>INLINK</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>N/A</TD>
</TR>

<TR>
<TD>INBB</TD>
<TD>Input Link BB</TD>
<TD>INLINK</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>N/A</TD>
</TR>

<TR>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
</TR>

<TR>
<TD>INLL</TD>
<TD>Input Link LL</TD>
<TD>INLINK</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>N/A</TD>
</TR>

</TABLE>

<P>&nbsp;

<HR><A NAME="HEADING14-16"></A>
<H1>
4. Expressions</H1>

Like the Calc record, the scalcout record has a CALC field into which
you can enter an expression for the record to evaluate when it processes.  The resulting numeric value will be placed in the VAL field, and the resulting string value will be placed in the SVAL field.  VAL can then be used by the OOPT field (see <A HREF="#MARKER-9-1">Section 5, <I>Output Parameters</I></A>) to determine whether or not to write to the output link or post an output event. Either VAL and SVAL can also be written to the output link.  (If you elect to write an output value, the record will choose between VAL and SVAL, depending on the data type of the field at the other end of the output link.)

<P>&nbsp;The CALC expression is actually converted to opcodes and stored in
postfix notation in the RPCL field.  It is this expression which is actually
used to calculate VAL.  The postfix expression is evaluated more efficiently at
run-time than an infix expression would be.  When CALC is  changed at run-time,
the record-support routine <code>special()</code> will call a function to check
it, and convert it to postfix notation.

<BR>The record also has a second set of calculation-related fields described  in <A HREF="#MARKER-9-1">Section 5, <I>Output Parameters.</I></A>

<BR>&nbsp;
<TABLE BORDER>
<TR>
<TH>Field</TH>
<TH>Summary</TH>
<TH>Type</TH>
<TH>DCT</TH>
<TH>Initial</TH>
<TH>Access</TH>
<TH>Modify</TH>
<TH>Rec Proc Monitor</TH>
<TH>PP</TH>
</TR>

<TR>
<TD>CALC</TD>
<TD>Calculation</TD>
<TD>STRING[80]</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
</TR>

<TR>
<TD>VAL</TD>
<TD>Value</TD>
<TD>DOUBLE</TD>
<TD>No</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
</TR>

<TR>
<TD>RPCL</TD>
<TD>Reverse Polish</TD>
<TD>NOACCESS</TD>
<TD>No</TD>
<TD>0</TD>
<TD>No</TD>
<TD>No</TD>
<TD>N/A</TD>
<TD>No</TD>
</TR>

<TR>
<TD>SVAL</TD>
<TD>String value</TD>
<TD>STRING (40)</TD>
<TD>No</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
</TR>
</TABLE>

<P>
Expressions supported by the string calculation record can involve operands,
algebraic operators and functions, trigonometric functions, relational
operators, logical operators, string operators and functions, parentheses
and commas, and the conditional '?:' operator. The expression can consist
of any of these operators, as well as any of the values from the input
fields, which are the operands.

<P>&nbsp;Grouping of operands with parentheses is important not only to
specify the order in which operations are to be done, but also to distinguish
operands from operators whose names are spelled out, such as the logical
operator 'AND'.  The expression 'AANDB', which could have meant 'A AND B',
will be misinterpreted by the parser, which will interpret 'AA' as the name
of a string variable.

<A NAME="HEADING14-19"></A>

<H2> 4.1. Operands</H2>

The expression can use as operands the values retrieved from the input links,
and literal constants such as "abc", "1.5", and "23". (Numeric constants in
expressions must be either floating-point numbers, or integers in base ten. 
Numbers like "0x03" will not be understood by the expression parser.)  Values
retrieved from the input links are stored in the A-L, and AA-LL fields. The
values to be used in the expression are simply referenced by the field name. For
example, the value obtained from the INPA link is stored in the field A, and the
value obtained from INPB is stored in field B. The field names can be included
in the expression which will operate on their respective values, as in "A+B".

<P>
<TABLE BORDER>

<TR>
<TH>Field</TH>
<TH>Summary</TH>
<TH>Type</TH>
<TH>DCT</TH>
<TH>Initial</TH>
<TH>Access</TH>
<TH>Modify</TH>
<TH>Rec Proc Monitor</TH>
<TH>PP</TH>
</TR>

<TR>
<TD>A</TD>
<TD>Input Value A</TD>
<TD>DOUBLE</TD>
<TD>No</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes/No*</TD>
<TD>Yes</TD>
<TD>Yes</TD>
</TR>

<TR>
<TD>B</TD>

<TD>Input Value B</TD>
<TD>DOUBLE</TD>
<TD>No</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes/No*</TD>
<TD>Yes</TD>
<TD>Yes</TD>
</TR>

<TR>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
</TR>


<TR>
<TD>L</TD>
<TD>Input Value L</TD>
<TD>DOUBLE</TD>
<TD>No</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes/No*</TD>
<TD>Yes</TD>
<TD>Yes</TD>
</TR>

<TR><TD></TR>

<TR>
<TD>AA</TD>
<TD>Input string AA</TD>
<TD>STRING (40)</TD>
<TD>No</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes/No*</TD>
<TD>Yes</TD>
<TD>Yes</TD>
</TR>

<TR>
<TD>BB</TD>
<TD>Input string BB</TD>
<TD>STRING (40)</TD>
<TD>No</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes/No*</TD>
<TD>Yes</TD>
<TD>Yes</TD>
</TR>

<TR>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
</TR>

<TR>
<TD>LL</TD>
<TD>Input string LL</TD>
<TD>STRING (40)</TD>
<TD>No</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes/No*</TD>
<TD>Yes</TD>
<TD>Yes</TD>
</TR>

</TABLE>

<P>* If a valid input link is associated with this field, then it may
not be modified.

<P>&nbsp;There are a few special operands not associated with input fields, but
defined by the record (more exactly, defined by the calc engine the record uses
to evaluate expressions).  All but <code>RNDM</code> are constants.

<P><A NAME="HEADING14-20"></A>

<table border>

<tr>
<td align=center valign=top>PI
<td valign=top>3.141592654

<tr>
<td align=center valign=top>D2R
<td valign=top>Degrees to radians (PI/180)

<tr>
<td align=center valign=top>R2D
<td valign=top>Radians to degrees (1/D2R)

<tr>
<td align=center valign=top>S2R
<td valign=top>Arc seconds to radians (D2R/3600)

<tr>
<td align=center valign=top>R2S
<td valign=top>Radians to arc seconds (1/S2R)

<tr>
<td align=center valign=top>RNDM
<td valign=top>Random number between 0 and 1.

</table>


<A NAME="HEADING14-21"></A>
<A NAME="Expressions"></A>
<H2>
4.2. Algebraic Functions/Operators</H2>

<table border>

<tr>
<th align=center valign=top>Op
<th valign=top>Description
<th valign=top>Example

<tr>
<td align=center valign=top>ABS
<td valign=top>Absolute value (one-argument function)
<td><code>ABS(A)</code>

<tr>
<td align=center valign=top>SQRT
<td valign=top>Square root (one-argument function) (SQR is deprecated)
<td><code>SQRT(A)</code>

<tr>
<td align=center valign=top>MIN
<td valign=top>Minimum (two-or-more-argument function)
<td><code>MIN(A,B,C)</code>

<tr>
<td align=center valign=top>MAX
<td valign=top>Maximum (two-or-more-argument function)
<td><code>MAX(A,B,C)</code>

<tr>
<td align=center valign=top>CEIL
<td valign=top>Ceiling (one-argument function)
<td><code>CEIL(A)</code>

<tr>
<td align=center valign=top>FLOOR
<td valign=top>Floor (one-argument function)
<td><code>FLOOR(A)</code>

<tr>
<td align=center valign=top>INT
<td valign=top>Nearest integer (one-argument function)
<td><code>INT(A)</code>

<tr>
<td align=center valign=top>NINT
<td valign=top>Nearest integer (one-argument function)
<td><code>NINT(A)</code>

<tr>
<td align=center valign=top>LOG
<td valign=top>Log base 10 (one-argument function)
<td><code>LOG(A)</code>

<tr>
<td align=center valign=top>LN
<td valign=top>Natural logarithm (one-argument function)
<td><code>LN(A)</code>

<tr>
<td align=center valign=top>LOGE
<td valign=top>Deprecated synonym for 'LN'
<td><code>LOGE(A)</code>

<tr>
<td align=center valign=top>EXP
<td valign=top>Exponential function (unary)
<td><code>EXP(A)</code>

<tr>
<td align=center valign=top>^
<td valign=top>Exponential (binary) (Same as '**'.)
<td><code>A^B</code>

<tr>
<td align=center valign=top>**
<td valign=top>Exponential (binary) (Same as '^'.)
<td><code>A**B</code>

<tr>
<td align=center valign=top>+
<td valign=top>Addition (binary)
<td><code>A+B</code>

<tr>
<td align=center valign=top>-
<td valign=top>Subtraction (binary)
<td><code>A-B</code>

<tr>
<td align=center valign=top>*
<td valign=top>Multiplication (binary)
<td><code>A*B</code>

<tr>
<td align=center valign=top>/
<td valign=top>Division (binary)
<td><code>A/B</code>

<tr>
<td align=center valign=top>%
<td valign=top>Modulo (binary)
<td><code>A%B</code>


<tr>
<td align=center valign=top>-
<td valign=top>Negate (unary)
<td><code>-A</code>

<tr>
<td align=center valign=top>NOT
<td valign=top>Negate (unary)
<td><code>NOT A</code>

<tr>
<td align=center valign=top>&gt;&amp;
<td valign=top>Max (binary)
<td><code>A>?B</code>

<tr>
<td align=center valign=top>&lt;&amp;
<td valign=top>Min (binary)
<td><code>A&lt;?B</code>

</table>

<P>
<A NAME="HEADING14-39"></A>
<H2>
4.3. Trigonometric Functions</H2>

<table border>

<tr>
<th align=center valign=top>Op
<th valign=top>Description
<th valign=top>Example

<tr>
<td align=center valign=top>SIN
<td valign=top>Sine (one-argument function)
<td><code>SIN(A)</code>

<tr>
<td align=center valign=top>SINH
<td valign=top>Hyperbolic sine (one-argument function)
<td><code>SINH(A)</code>

<tr>
<td align=center valign=top>ASIN
<td valign=top>Arc sine (one-argument function)
<td><code>ASIN(A)</code>

<tr>
<td align=center valign=top>COS
<td valign=top>Cosine (one-argument function)
<td><code>COS(A)</code>

<tr>
<td align=center valign=top>COSH
<td valign=top>Hyperbolic cosine (one-argument function)
<td><code>COSH(A)</code>

<tr>
<td align=center valign=top>ACOS
<td valign=top>Arc cosine (one-argument function)
<td><code>ACOS(A)</code>

<tr>
<td align=center valign=top>TAN
<td valign=top>Tangent (one-argument function)
<td><code>TAN(A)</code>

<tr>
<td align=center valign=top>TANH
<td valign=top>Hyperbolic tangent (one-argument function)
<td><code>TANH(A)</code>

<tr>
<td align=center valign=top>ATAN
<td valign=top>Arc tangent (one-argument function)
<td><code>ATAN(A)</code>

<tr>
<td align=center valign=top>ATAN2
<td valign=top>Alternate form of arctangent (two-argument function)
<td><code>ATAN2(A,B)</code>

</table>

<P>
<A NAME="HEADING14-49"></A>
<H2>
4.4. Relational Operators</H2>

<table border>

<tr>
<th align=center valign=top>Op
<th valign=top>Description
<th valign=top>Example

<tr>
<td align=center valign=top>>=
<td valign=top>Greater than or equal to
<td><code>A&gt;=B</code>

<tr>
<td align=center valign=top>>
<td valign=top>Greater than
<td><code>A&gt;B</code>

<tr>
<td align=center valign=top>&lt;=
<td valign=top>Less than or equal to
<td><code>A&lt;=B</code>

<tr>
<td align=center valign=top>&lt;
<td valign=top>Less than
<td><code>A&lt;B</code>

<tr>
<td align=center valign=top>!=
<td valign=top>Not equal to (same as '#')
<td><code>A!=B</code>

<tr>
<td align=center valign=top>#
<td valign=top>Not equal to (same as '!=')
<td><code>A#B</code>

<tr>
<td align=center valign=top>==
<td valign=top>Equal to (same as '=')
<td><code>A==B</code>

<tr>
<td align=center valign=top>=
<td valign=top>Equal to (same as '==')
<td><code>A=B</code>

</table>

<P>
<A NAME="HEADING14-56"></A>
<H2>
4.5. Logical Operators</H2>

<table border>

<tr>
<th align=center valign=top>Op
<th valign=top>Description
<th valign=top>Example

<tr>
<td align=center valign=top>&amp;&amp;
<td valign=top>Logical AND
<td><code>A&amp;&amp;B</code>

<tr>
<td align=center valign=top>||
<td valign=top>Logical OR
<td><code>A||B</code>

<tr>
<td align=center valign=top>!
<td valign=top>Logical NOT
<td><code>!A</code>

</table>

<P>
<A NAME="HEADING14-60"></A>
<H2>
4.6. Bitwise Operators</H2>

<table border>

<tr>
<th align=center valign=top>Op
<th valign=top>Description
<th valign=top>Example

<tr>
<td align=center valign=top>|
<td valign=top>Bitwise OR
<td><code>A|B</code>

<tr>
<td align=center valign=top>OR
<td valign=top>Bitwise OR
<td><code>A OR B</code>

<tr>
<td align=center valign=top>&amp;
<td valign=top>Bitwise AND
<td><code>A&amp;B</code>

<tr>
<td align=center valign=top>AND
<td valign=top>Bitwise AND
<td><code>A AND B</code>

<tr>
<td align=center valign=top>XOR
<td valign=top>Bitwise Exclusive OR
<td><code>A XOR B</code>

<tr>
<td align=center valign=top>~
<td valign=top>One's Complement
<td><code>~A</code>

<tr>
<td align=center valign=top>&lt;&lt;
<td valign=top>Left shift
<td><code>A&lt;&lt;B</code>

<tr>
<td align=center valign=top>&gt;&gt;
<td valign=top>Right shift
<td><code>A&gt;&gt;B</code>
</table>


<P>
<A NAME="HEADING14-69"></A>
<H2>
4.7. Special Characters </H2>

<P>Parentheses, and nested parentheses are permitted (sometimes required) in expressions.

<P>The comma is required to separate the arguments of a binary function.

<P>Quotes of two kinds (" and ') are permitted to indicate the beginning and end of a string expression. 
The expression parser treats these quote characters in exactly the same way, so you can use pairs of
either.  Using one kind of quote allows you to include the other kind in a string.  Note that string calc
expressions defined in an EPICS database must use the ' character to delimit embedded strings, because
database tools will use " to delimit the entire expression.  

<P>Escape sequences understood by the Epics routines dbTranslateEscape() and
epicsStrSnEscaped() are permitted in strings handled by the scalcout record,
and the sCalc engine supplies functions that encode and decode escaped
strings.  Here's the current escape list:<br>
<code> \a \b \f \n \r \t \v \\ \? \' \" \000 \xhh</code><br>

<P>Note that '\000' represents an octal number, and may include one, two, or
three octal digits.  \xhh is a two-digit hexadecimal number.

<P>See the Application Developer's Guide for more on this topic.

<P><A NAME="HEADING14-72"></A>
<H2>
4.8. Conditional Expression</H2>

The C language's question mark operator is supported. The format is:

<PRE>&nbsp;&lt;expression&gt; ? &lt;expression-true result&gt; : &lt;expression-false  result&gt;</PRE>


<P>
<A NAME="HEADING14-73"></A>
<H2>
4.9. String Functions/Operators</H2>

Most two-argument string functions and binary string operators are "overloaded"
numeric functions and operators that perform string operations only if
both of their arguments/operands are strings.

<P><table border>
<tr>
<th align=center valign=top>Op
<th valign=top>Description
<th valign=top>Example

<tr>
<td align=center valign=top>MIN
<td valign=top>Minimum lexically (two-or-more-argument function)
<td><code>MAX('a','b','c') -> 'a'</code>

<tr>
<td align=center valign=top>MAX
<td>Maximum lexically (two-or-more-argument function)
<td><code>MAX('a','b','c') -> 'c'</code>

<tr>
<td align=center valign=top>INT
<td>Find first number in string; return nearest integer (one-argument
function)
<td><code>INT('1.9') -> 1</code>
<td><code>INT('abc1.9') -> 1</code>

<tr>
<td align=center valign=top>NINT
<td>Find first number in string; return nearest integer (one-argument
function)
<td><code>NINT('1.9') -> 2</code>
<td><code>NINT('abc1.9') -> 2</code>

<tr>
<td align=center valign=top>+
<td>Concatenate (binary)
<td><code>'a'+'b' -> 'ab'</code>

<tr>
<td align=center valign=top>-
<td>Delete first occurrence of substring (binary)
<td><code>'abca'-'a' -> 'bca'</code>

<tr>
<td align=center valign=top>-|
<td>Delete first occurrence of substring (binary)
<td><code>'abca'-|'a' -> 'bca'</code>

<tr>
<td align=center valign=top>|-
<td>Delete last occurrence of substring (binary)
<td><code>'abca'|-'a' -> 'abc'</code>

<tr>
<td align=center valign=top>&gt;=
<td>Lexically greater than or equal (binary)
<td><code>'a'&gt;='b' -> 0</code>

<tr>
<td align=center valign=top>&gt;
<td>Lexically greater than (binary)
<td><code>'a'&gt;'b' -> 0</code>

<tr>
<td align=center valign=top>&lt;=
<td>Lexically less than or equal (binary)
<td><code>'a'&lt;='b' -> 1</code>

<tr>
<td align=center valign=top>&lt;
<td>Lexically less than (binary)
<td><code>'a'&lt;'b' -> 1</code>

<tr>
<td align=center valign=top>!=
<td>Lexically not equal to (binary)
<td><code>'a'!='b' -> 1</code>

<tr>
<td align=center valign=top>==
<td>Lexically equal to (binary)
<td><code>'a'=='b' -> 0</code>

<tr>
<td align=center valign=top>&gt;&gt;
<td>Right shift characters (fill behind with spaces). (binary)
<td><code>'abc'&gt;&gt;2 -> '  abc'</code>

<tr>
<td align=center valign=top>&lt;&lt;
<td>Left shift characters. (binary)
<td><code>'abc'&lt;&lt;2 -> 'c'</code>

<tr>
<td align=center valign=top>DBL
<td>Convert argument to double (one-argument function)
<td><code>DBL('1') -> 1.0</code>
<td><code>DBL('abc1.23') -> 1.23</code>

<tr>
<td align=center valign=top>STR
<td>Convert argument to string (one-argument function)
<td><code>STR(1) -> '1.00000000'</code>

<tr>
<td align=center valign=top>BYTE
<td>Convert first character of string argument to double (one-argument function)
<td><code>BYTE('abc') -> 97.0</code>

<tr>
<td align=center valign=top>PRINTF
<td valign=top>Return string constructed from format string and string or
double argument (two-argument function)&nbsp; (NOTE: '$P' is a synonym for PRINTF)

<BR>Allowed format indicators: <B>%cdeEfgGiosuxX</B>
<BR>Disallowed indicators:<B> *</B>
<td><code>PRINTF("%.2f",1.23) -> '1.23'</code>

<tr>
<td align=center valign=top>SSCANF
<td>Return string or double parsed from string argument according
to format string (two-argument function) (NOTE: '$S' is a synonym for SSCANF)

<BR>Allowed format indicators: <B>%*[cdeEfgGhilosuxX</B>
<BR>Disallowed indicators: <B>$npw</B>
<td><code>SSCANF('V=1.25', "%*2c%lf") -> 1.25</code>

<tr>
<td align=center valign=top><font color="blue">READ</font>
<td>Read binary data.  This function is similar in form to SSCANF, and is roughly
analogous in function, but it operates on binary data.  The first argument is
the string from which data is to be copied.  If this string contains any unprintable
characters, they will have been converted to escape sequences by the software that
transported them to this point.  READ() converts this string to a raw binary array,
using the EPICS function dbTranslateEscape(), copies bytes from that array
into a temporary numeric variable, whose type depends on the format string,
converts the result to double, and returns this value.
<br>(NOTE: '$R' is a synonym for READ)

<P>The format string is similar to that of the SSCANF function, but only the
following subset of format indicators is supported:
<table border>
<tr><th>format<th>resulting behavior
<tr><td>%i %d<td>copy four bytes to a long signed integer
<tr><td>%hi %hd<td>copy two bytes to a short signed integer
<tr><td>%o %u %x %X<td>copy four bytes to a long unsigned integer
<tr><td>%ho %hu %hx %hX<td>copy two bytes to a short unsigned integer
<tr><td>%e %E %f %g %G<td>copy four bytes to a float
<tr><td>%le %lE %lf %lg %lG<td>copy eight bytes to a double
<tr><td>%c<td>copy one byte to a signed character
<tr><td>%*<td>suppress assignment to next conversion indicator.  Only one '%*'
is honored. <br>
<em>This is the only reliable way to skip past a specified number of bytes in a
binary input string.  For a non-escaped string, something like '<code>aa[3,5]</code>'
would have worked as well.  But if the string <code>aa</code> might include
escape sequences, character offsets in the escaped string will depend on the
values of the characters, because printable characters are not escaped.</em>
</table>

<BR>Allowed format indicators: <B>%*cdeEfgGhilouxX</B>
<BR>Disallowed indicators: <B>$npw[s</B>
<td><code>READ('\x01\x02', "%hu") -> 258</code><br><br>
<code>READ('\x01\x02', "%*c%hu") -> 2</code><br>
<tr>
<td align=center valign=top><font color="blue">WRITE</font>
<td>Write binary data.  This function is similar in form to PRINTF, and is roughly
analogous in function, but it operates on binary data.  The first argument is the
format string; the second is the data to be written.  After the data have been
written to a buffer, the buffer is processed by epicsStrSnEscaped() and returned.
<br>(NOTE: '$W' is a synonym for WRITE)

<P>The format string is similar to that of the PRINTF function, but only the
following subset of format indicators is supported:
<table border>
<tr><th>format<th>resulting behavior
<tr><td>%i %d<td>convert to a long signed integer and write four bytes
<tr><td>%hi %hd<td>convert to to a short signed integer and copy two bytes
<tr><td>%o %u %x %X<td>convert to a long unsigned integer and copy four bytes
<tr><td>%ho %hu %hx %hX<td>convert to a short unsigned integer and copy two bytes 
<tr><td>%e %E %f %g %G<td>convert to a float and copy four bytes 
<tr><td>%le %lE %lf %lg %lG<td>convert to a double and copy eight bytes 
<tr><td>%c<td>convert to a signed character and copy one byte
</table>

<BR>Allowed format indicators: <B>%cdeEfgGhilouxX</B>
<BR>Disallowed indicators: <B>$npw[s</B>
<td><code>WRITE('%hd', 1250) -> '\004\342'</code>




<tr>
<td align=center valign=top><font color="blue">TR_ESC</font>
<td>Translate escape sequences into the characters they represent
(one-argument function).   (NOTE: '$T' is a synonym for TR_ESC.)
<BR>TR_ESC() applies dbTranslateEscape() to its argument. 
<BR>This function is approximately the opposite of ESC().
<BR>An escaped null character will terminate the result string
<td><code>TR_ESC("a\x62c") -> 'abc'</code>

<tr>
<td align=center valign=top><font color="blue">ESC</font>
<td>Translate escape characters into equivalent escape sequences.
(one-argument function) (NOTE: '$E' is a synonym for ESC)
<BR>ESC() applies epicsStrSnEscaped() to its argument. 
<BR>This function is approximately the opposite of TR_ESC().
<BR>The first null character found in the input string terminates it.
If there is no null chaacter, the string is assumed to be 40
characters long.
<td><code>ESC("a&lt;return&gt;c") -> 'a\rc'</code>

<tr>
<td align=center valign=top><font color="blue">CRC16</font>
<td>Calculate Modbus/RTU 16-bit CRC and return it as an escaped string. 
<td><code>CRC16('\x01\x03') -> '\x01\x03\x40\x21'</code>

<tr>
<td align=center valign=top><font color="blue">MODBUS</font>
<td>Calculate Modbus/RTU 16-bit CRC and append it, as an escaped string,
to the argument. 
<td><code>CRC16('\x01\x03') -> '\x40\x21'</code>

<tr>
<td align=center valign=top><font color="blue">LRC</font>
<td>Calculate Modbus/ASCII 8-bit LRC and return it as an escaped string. 
<td><code>LRC('\x01\x03') -> '\xfc'</code>

<tr>
<td align=center valign=top><font color="blue">AMODBUS</font>
<td>Calculate Modbus/ASCII 8-bit LRC and append it, as an escaped string,
to the argument.  Note that this doesn't do everything needed for an actual
device.  The string is supposed to be converted to binary, have its LRC
appended, and ':' prepended.  Then the whole thing then gets converted to
ASCII characters. 
<td><code>AMODBUS('\x01\x03') -> '\x01\x03\xfc'</code>

<tr>
<td align=center valign=top><font color="blue">XOR8</font>
<td>Calculate 8-bit XOR checksum and return it as an escaped string. 
<td><code>XOR8('\x01\x03') -> '\x02'</code>

<tr>
<td align=center valign=top><font color="blue">ADD_XOR8</font>
<td>Calculate 8-bit XOR checksum and append it, as an escaped string,
to the argument. 
<td><code>ADD_XOR8('\x01\x03') -> '\x01\x03\x02'</code>

<tr>
<td align=center valign=top>LEN
<td>Return length of string argument. If arg is not a string, it will be converted
to string.
<td><code>LEN('abc') -> 3</code>

<tr>
<td align=center valign=top>[
<td>Substring
<td><code>'abcdef'[1,3] -> 'bcd'</code>
<code><BR>'abcdef'['ab','ef'] -> 'cd'</code>
<code><BR>'abcdef'[0,-1] -> 'abcdef'</code>

<tr>
<td align=center valign=top>{
<td>Substring substitution
<td><code>'abcdef'{'cd','XX'} -> 'abXXef'</code>

<tr>
<td align=center valign=top>"
<td>String indicator
<td><code>"abc"</code>

<tr>
<td align=center valign=top>'
<td>String indicator
<td><code>'abc'</code>

<tr>
<td valign=top colspan=3> <font color="blue">Functions and operators rendered in
this color are experimental.  The names or implementations may change in a future
version of this software.</font>
</table>

<A NAME="HEADING14-74"></A>
<H2>
4.10. Array Operators</H2>

<table border>

<tr>
<th align=center valign=top>Op
<th valign=top>Description
<th valign=top>Example

<tr>
<td align=center valign=top>@
<td>Numeric array element.  Regard the numeric fields A-L as an array whose elements
are numbered 0-11, and return the element whose number follows.  (unary)
<td><code>@A</code>

<tr>
<td align=center valign=top>@@
<td>String array element.  Regard the string fields AA-LL as an array of strings whose
elements are numbered 0-11, and return the element whose number follows.  (unary)
<td><code>@@A</code>

</table>

<A NAME="HEADING14-75"></A>
<H2>
4.11. Miscellaneous Operators</H2>

<table border>

<tr>
<th align=center valign=top>Op
<th valign=top>Description
<th valign=top>Examples

<tr>
<td align=center valign=top>:=
<td>Store value of right hand side in location specified by left hand side.  (binary)
<td><code>A:=1.2</code>
<code><BR>@7:='abc'</code>
<code><BR>AA:='abc'</code>
<code><BR>@@4:='abc'</code>

<tr>
<td align=center valign=top>UNTIL
<td>Execute expression until its value is TRUE.  (binary)<br>

The total number of iterations is limited to the ioc-shell variable
sCalcLoopMax, which defaults to 1000.

<td><code>until(1)</code>
<code><BR>until(a:=a+1;b:=b-1;b<1)</code>

</table>

<A NAME="HEADING14-76"></A>
<H2>
4.12. Examples</H2>

<hr>
<A NAME="HEADING14-77"></A>
<H3>Algebraic</H3>

<DL>
<DT><B><CODE>A + B + 10</B></CODE>
<DD>Result is <CODE>A + B + 10</CODE>
</DL>

<hr>
<P><A NAME="HEADING14-79"></A>
<H3>Relational</H3>

<DL>
<DT><b><CODE>(A + B) &lt; (C + D)</CODE></b>
<DD>Result is <CODE>1</CODE> if <CODE>(A+B) &lt; (C+D)</CODE>
<BR>Result is <CODE>0</CODE> if <CODE>(A+B) >= (C+D)</CODE>
</DL>

<hr>
<P><A NAME="HEADING14-83"></A>
<H3>Question Mark</H3>

<DL>
<DT><b><CODE>(A+B)&lt;(C+D)?E:F+L+10</CODE></b>
<DD>Result is <CODE>E</CODE> if <CODE>(A+B) &lt; (C+D)</CODE>
<BR>Result is <CODE>F+L+10</CODE> if <CODE>(A+B) >= (C+D)</CODE>

<P><DT><b><CODE>(A+B)&lt;(C+D)?E</CODE></b>
<DD>Result is <CODE>E</CODE> if (A+B) &lt; (C+D)
<BR>Result is unchanged if <CODE>(A+B) >= (C+D)</CODE>
</DL>

<hr>
<P><A NAME="HEADING14-91"></A>
<H3>Logical</H3>

<DL>
<DT><b><CODE>A&amp;B</CODE></b>
<DD>Causes the following to occur:

<OL>
<LI>Convert <CODE>A</CODE> to integer
<LI>Convert <CODE>B</CODE> to integer
<LI>Perform bit-wise <CODE>AND</CODE> of <CODE>A</CODE> and <CODE>B</CODE>
<LI>Convert result to floating point
</OL>
</DL>

<hr>
<P><A NAME="HEADING14-92"></A>
<H3>String</H3>
<DL>
<DT><B><CODE>A + "abc"</CODE></B><BR>
<B><CODE>A + "abc1.2"</B></CODE><BR>
<B><CODE>A + AA</CODE></B>&nbsp;&nbsp;<I>(where AA = "abc1.2")</I>
<DD>Result is <CODE>A</CODE>.&nbsp; The strings <CODE>"abc"</CODE> and
<CODE>"abc1.2"</CODE> will be converted implicitly to the number <CODE>0</CODE>.

<P><DT><B><CODE>A + DBL("abc1.2")</CODE></B>
<DD>Result is <CODE>A + 1.2</CODE>.&nbsp; Explicit conversion to a number
(by <CODE>DBL</CODE>, <CODE>INT</CODE>, or <CODE>NINT</CODE>) is more
aggressive than implicit conversion, and skips leading non-numeric characters.

<P><DT><B><CODE>"abc" + "def"</CODE></B>
<DD>Result is <CODE>"abcdef"</CODE>.

<P><DT><B><CODE>PRINTF("abc%1.2f", A)</CODE></B>&nbsp;<I>(where A = 1.2345)</I>
<DD>Result is&nbsp; <CODE>"abc1.23"</CODE>.

<P>NOTE: unlike the c-language function
<BR>printf(&lt;format>,&lt;arg1>,&lt;arg2>,...),
<BR>this function accepts only one argument after the format string.

<P><DT><B><CODE>SSCANF(AA, "%*3c%lf")</CODE></B>&nbsp;<I>(where AA = "abc1.2")</I>
<DD>Result is <CODE>"1.20000000"</CODE>.&nbsp; (The format fragment
<CODE>"%*3c"</CODE> directs sscanf to ignore three characters.)

<BR>NOTE: unlike the c-language function
<BR>sscanf(&lt;source>,&lt;format>,&lt;dest1>,&lt;dest2>,...),
<BR>this function cannot store to a variable, but only to the value
stack.

<P><DT><B><CODE>BYTE("ABC")</CODE></B>
<DD>Result is <CODE>65</CODE>, the ASCII code for "A" in decimal.

<P><DT><B><CODE>"abcdef"[2,4]</CODE></B>
<DD>Result is <CODE>"cde"</CODE>.&nbsp; (The first character of the string
is numbered "0".)

<P><DT><B><CODE>"abcdef"[-2,-1]</CODE></B>
<DD>Result is <CODE>"ef"</CODE>.&nbsp; (The last character of the string is
numbered "-1".)

<P><DT><B><CODE>"abcdef"["ab","ef"]</CODE></B>
<DD>Result is <CODE>"cd"</CODE>.&nbsp; (If the first argument is a string,
it returns the index of the first character <I>after</I> a successful match,
or the first character in the string if no match was found.&nbsp; If the
second argument is a string, it returns the index of the last character
<i>before</i> a successful match, or the last character in the string if no
match was found.)

<P><DT><B><CODE>A==2 ? "yes" : "no"</CODE></B>
<DD>Result is <CODE>"yes"</CODE> if <CODE>A == 2</CODE>; otherwise, result
is <CODE>"no"</CODE>.

<P><DT><B><CODE>"abcdef"{"bcd","dcb"}</CODE></B>
<DD>Result is <CODE>"adcbef"</CODE>.

<P><DT><B><CODE>"abcdef"{"zzz","dcb"}</CODE></B>
<DD>Result is <CODE>"abcdef"</CODE>.&nbsp; (If no match, then no replacement.)

<P><DT><B><CODE>"abcdef"[1,-2][1,-2]</CODE></B>
<DD>Result is <CODE>"cd"</CODE>
</DL>

<hr>
<A NAME="HEADING14-93"></A>
<H3>
Argument array</H3>

<DL>
<DT><B><CODE>@0</CODE></B>
<DD>Result in the value of the numeric variable <CODE>A</CODE>.  ("<CODE>@0</CODE>"
is just another name for <CODE>A</CODE>.)<P>

<DT><B><CODE>@@0</CODE></B>
<DD>Result in the value of the string variable AA.<P>

<DT><B><CODE>@(A+B)</CODE></B>
<DD>Result in the value of the numeric variable whose number is given by the sum
of A and B.<P>

<DT><B></B>
<DD>
<P>
</DL>

<hr>
<A NAME="HEADING14-94"></A>
<H3>
Store</H3>

The "Store" operator is the only string-calc operator that does not produce a
value.  Thus, the expression <B><code>a:=0</code></B> is an incomplete and therefore illegal calc expression,
because it leaves us with nothing to write to the record's <code>VAL</code> field.

<DL>
<DT><B><CODE>A:=A-1;7</CODE></B>

<DD>Evaluate the expression <CODE>A-1</CODE>, store the result in the input
variable <CODE>A</CODE>, and set the VAL field to 7.<P>

<DT><B><CODE>@0:=A-1;7</CODE></B>
<DD>Same as above, because <CODE>@0</CODE> is just another name for <CODE>A</CODE><P>

<DT><B><CODE>D:=0;@D:=A-1;7</CODE></B>
<DD>Same as above, because <CODE>D==0</CODE>.<P>

<DT><B><CODE>AA:="abc";7</CODE></B>
<DD>Overwrite the string input variable <CODE>AA</CODE> with the string 'abc', and set the VAL field to 7.<P>

<DT><B><CODE>AA:="abc";b:=0;7</CODE></B>

<DD>Multiple store expressions, separated by ';' terminators, are legal at top
level, but - as always - the expression as a whole must produce a value.  This expression
produces the value <code>7</code>.<P>

<DT><B><CODE>A+(AA:="abc";b:=0;7)</CODE></B>

<DD>Multiple store expressions are also legal within parentheses, and again the
parenthesized subexpression must produce a value.  The parenthesized
subexpression in this example produces the value <code>7</code>, which is added to
<code>A</code>.

</DL>

<hr>
<A NAME="HEADING14-95"></A>
<H3>
Loop ("UNTIL")</H3>

The <code>UNTIL</code> function evaluates its expression repeatedly until the
expression returns a nonzero value, or the allowed number of iterations
<code>sCalcLoopMax</code> has been reached.  When looping is done, or aborted,
the expression value is returned.

<DL>
<DT><B><CODE>UNTIL(1)</CODE></B>

<DD>The expression 1 is evaluated, terminates the loop, and is returned.  This
do-nothing expression is equivalent to <code>(1)</code>.<P>

<DT><B><CODE>B:=10;UNTIL(B:=B-1;B<1)</CODE></B> <DD>This do-almost-nothing
expression initializes B to 10, decrements it repeatedly until its value is
zero, and returns the value 1 (True).<P>

<DT><B><CODE>B:=9; AA:=''; UNTIL(AA:=AA+CC[B,B]; B:=B-1; B<0)</CODE></B>

<DD>If we start with <CODE>CC='abcdefghij'</CODE>, this expression loops
backwards through <CODE>CC</CODE>, appending characters to produce
<CODE>AA='jihgfedcba'</CODE>.<P>

<DT><B><CODE>B:=0;AA:='';UNTIL(AA:=AA+(CC[b,b]==','?'':CC[b,b]);B:=B+1;B>LEN(CC))</CODE></B>

<DD>This expression copies CC to AA, leaving out the commas.<P>

<DT><B><CODE>AA:='';B:=1;UNTIL(A:=0;C:=UNTIL(AA:=AA+(@@B)[A,A];A:=A+1;A>1);B:=B+1;B>12)</CODE></B>

<dd>This nested loop copies the first two characters from each of the
string-input fields BB-LL, and appends them to AA.  Note that the inner "UNTIL"
function produces a value that must be discarded (by storing it to C), because
it is part of the outer UNTIL function's expression.  That expression must
produce a single value, which the UNTIL function uses to determine when it's
done.

</DL>






<P>&nbsp;
<HR><A NAME="HEADING14-98"></A>
<H1>
5.&nbsp;<A NAME="MARKER-9-1"></A>Output Parameters</H1>

These parameters specify and control the output capabilities of the
scalcout record. They determine when to write the output, where to write
it, and what the output will be. The OUT link specifies the Process Variable
to which the result will be written. The OOPT field determines the condition
that causes the output link to be written to. It's a menu field that has
six choices:

<P><table border>
<tr><td valign=top>
<TT>Every Time</TT><td valign=top>write output every time record is processed.


<tr><td valign=top>
<TT>On Change</TT><td valign=top>write output every time VAL changes, i.e., every
time the result of the expression changes.


<tr><td valign=top>
<TT>When Zero</TT><td valign=top>when record is processed, write output if VAL is
zero.


<tr><td valign=top>
<TT>When Non-zero</TT><td valign=top>when record is processed, write output if VAL
is non-zero.


<tr><td valign=top>
<TT>Transition to Zero</TT><td valign=top>when record is processed, write output only
if VAL is zero and last value was non-zero.


<tr><td valign=top>
<TT>Transition to Non-zero</TT><td valign=top>when record is processed, write output
only if VAL is non-zero and last value was zero.

<tr><td valign=top>
<TT>Never</TT><td valign=top>Don't write output ever.

</table>


<P>&nbsp;
The DOPT field determines what data is written to the output link when
the output is executed. The field is a menu field with two options: <TT>Use
CALC</TT> or <TT>Use OCAL</TT>. If <TT>Use CALC</TT> is specified, when
the record writes its output it will write the result of the expression
in the CALC record, that is, it will write the value of the VAL [SVAL]
field to a double [string] destination. If <TT>Use OCAL</TT> is specified,
the record will instead write the result of the expression in the OCAL
field, which is contained in the OVAL field (string result in the OSV)
field. The OCAL field is exactly like the CALC field and has the same functionality:
it can contain the string representation of an expression which is evaluated
at run-time. Thus, if necessary, the record can use the result of the CALC
expression to determine if data should be written and can use the result
of the OCAL expression as the data to write.

<P>&nbsp;If the OEVT field specifies a non-zero integer and the condition
in the OOPT field is met, the record will post a corresponding event. If
the ODLY field is non-zero, the record pauses for the specified number
of seconds before executing the OUT link or posting the output event. During
this waiting period the record is "active" and will not be processed again
until the wait is over. The field DLYA is equal to 1 during the delay period.
The resolution of the delay entry is 1/60 of a second (it uses the VxWorks
<TT>tickLib</TT>).

<P>&nbsp;The IVOA field specifies what action to take with the OUT link
if the scalcout record enters an INVALID alarm status. The options are
<TT>Continue normally</TT>, <TT>Don't drive outputs</TT>, and <TT>Set output
to IVOV</TT>. If the IVOA field is <TT>Set output to IVOV</TT>, the data
entered into the IVOV field is written to the OUT link if the record alarm
severity is INVALID.

<P>
<TABLE BORDER>
<TR>
<TH>Field</TH>
<TH>Summary</TH>
<TH>Type</TH>
<TH>DCT</TH>
<TH>Initial</TH>
<TH>Access</TH>
<TH>Modify</TH>
<TH>Rec Proc Monitor</TH>
<TH>PP</TH>
</TR>

<TR>
<TD>OUT</TD>
<TD>Output Specification</TD>
<TD>OUTLINK</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>N/A</TD>
<TD>No</TD>
</TR>

<TR>
<TD>OOPT</TD>
<TD>Output Execute Option</TD>
<TD>Menu</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>DOPT</TD>
<TD>Output Data Option</TD>
<TD>Menu</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>OCAL</TD>
<TD>Output Calculation</TD>
<TD>STRING[36]</TD>
<TD>Yes</TD>
<TD>Null</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>OVAL</TD>
<TD>Output Value</TD>
<TD>DOUBLE</TD>
<TD>No</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
</TR>

<TR>
<TD>OEVT</TD>
<TD>Event To Issue</TD>
<TD>SHORT</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>ODLY</TD>
<TD>Output Execution Delay</TD>
<TD>FLOAT</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>IVOV</TD>
<TD>Invalid Output Action</TD>
<TD>Menu</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>IVOA</TD>
<TD>Invalid Output Value</TD>
<TD>DOUBLE</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>OSV</TD>
<TD>Output string value</TD>
<TD>STRING[40]</TD>
<TD>NO</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
</TR>

<TR>
<TD>WAIT</TD>
<TD>Wait for completion?</TD>
<TD>Menu</TD>
<TD>Yes</TD>
<TD>"NoWait"</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
</TR>
</TABLE>

<P> The scalcout record now uses device support to write to the
<code>OUT</code> link. Soft device supplied with the record is selected with
the .dbd specification <PRE> field(DTYP,"Soft Channel") </PRE>

This device support uses the record's <code>WAIT</code> field to determine
whether to wait for completion of processing initiated by the <code>OUT</code>
link before causing the record to execute its forward link.  The mechanism by
which this waiting for completion is performed requires that the
<code>OUT</code> link have the attribute <code>CA</code> -- i.e., the link text
looks something like

<p><code>  xxx:record.field <b>CA</b> NMS</code>

<p>Currently, the record does not try to ensure that <code>WAIT</code> and
<code>OUT</code> are compatibly configured.  If <code>WAIT</code> == "Wait",
but the link looks like

<p><code> xxx:record.field <b>PP</b> NMS</code>

<p>for example, then the record will not wait for completion before executing
its forward link.

<P>&nbsp;
<HR>
<P><A NAME="HEADING14-109"></A>
<H1>
6.&nbsp;<A NAME="MARKER-9-2"></A>Operator Display Parameters</H1>

These parameters are used to present meaningful data to the operator.
Some are also meant to represent the status of the record at run-time.
An example of an interactive MEDM display screen that displays the status
of the scalcout record is located here.

<P>The EGU field contains a string of up to 16 characters which is
supplied by the user and which describes the values being operated upon.
The string is retrieved whenever the routine <TT>get_units</TT> is called.
The EGU string is solely for an operator's sake and does not have to be
used.

<P>The HOPR and LOPR fields only refer to the limits of the VAL,
HIHI, HIGH, LOW, and LOLO fields. PREC controls the precision of the VAL
field.

<P>The INAV-INLV and IAAV-ILLV fields indicate the status of the
link to the PVs specified in the INPA-INPL and INAA-INLL fields, respectively.
The fields can have three possible values:

<P>&nbsp;
<table border>

<tr>
<td valign=top>Ext PV NC
<td valign=top>the PV wasn't found on this IOC and a Channel Access link hasn't
been established.
</tr>

<tr>
<td valign=top>Ext PV OK
<td valign=top>the PV wasn't found on this IOC and a Channel Access link has
been established.
</tr>

<tr>
<td valign=top>Local PV
<td valign=top>the PV was found on this IOC.
</tr>

<tr>
<td valign=top>Constant
<td valign=top>the corresponding link field is a constant.
</tr>

</table>

<P>The OUTV field indicates the status of the OUT link. It has the same possible
values as the INAV-INLV fields.

<P>The CLCV and OLCV fields indicate the validity of the expression
in the CALC and OCAL fields, respectively. If the expression is invalid,
the field is set to one.

<P>The DLYA field is set to one during the delay interval specified
in ODLY.

<P>See the EPICS Record Reference Manual, for more on the record name (NAME) and
description (DESC) fields.

<P>
<TABLE BORDER>
<TR>
<TH>Field</TH>
<TH>Summary</TH>
<TH>Type</TH>
<TH>DCT</TH>
<TH>Initial</TH>
<TH>Access</TH>
<TH>Modify</TH>
<TH>Rec Proc Monitor</TH>
<TH>PP</TH>
</TR>

<TR>
<TD>EGU</TD>
<TD>Engineering Units</TD>
<TD>STRING [16]</TD>
<TD>Yes</TD>
<TD>Null</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>PREC</TD>
<TD>Display Precision</TD>
<TD>SHORT</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>HOPR</TD>
<TD>High Operating Range</TD>
<TD>FLOAT</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>LOPR</TD>
<TD>Low Operating Range</TD>
<TD>FLOAT</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>INAV</TD>
<TD>Link Status of INPA</TD>
<TD>Menu</TD>
<TD>No</TD>
<TD>1</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>INBV</TD>
<TD>Link Status of INPB</TD>
<TD>Menu</TD>
<TD>No</TD>
<TD>1</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
</TR>

<TR>
<TD>INLV</TD>
<TD>Link Status of INPL</TD>
<TD>Menu</TD>
<TD>No</TD>
<TD>1</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>OUTV</TD>
<TD>OUT PV Status</TD>
<TD>Menu</TD>
<TD>No</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>CLCV</TD>
<TD>CALC Valid</TD>
<TD>LONG</TD>
<TD>No</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>OCLV</TD>
<TD>OCAL Valid</TD>
<TD>LONG</TD>
<TD>No</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>DLYA</TD>
<TD>Output Delay Active</TD>
<TD>USHORT</TD>
<TD>No</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>NAME</TD>
<TD>Record Name</TD>
<TD>STRING [29]</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>DESC</TD>
<TD>Description</TD>
<TD>STRING [29]</TD>
<TD>Yes</TD>
<TD>Null</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>IAAV</TD>
<TD>Link Status of INAA</TD>
<TD>Menu</TD>
<TD>No</TD>
<TD>1</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>IBBV</TD>
<TD>Link Status of INBB</TD>
<TD>Menu</TD>
<TD>No</TD>
<TD>1</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
</TR>

<TR>
<TD>ILLV</TD>
<TD>Link Status of INLL</TD>
<TD>Menu</TD>
<TD>No</TD>
<TD>1</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
<TD>No</TD>
</TR>
</TABLE>
&nbsp;

<HR>
<P><A NAME="HEADING14-122"></A>
<H1>
7. Alarm Parameters</H1>

The possible alarm conditions for the scalcout record are the SCAN,
READ, Calculation, and limit alarms. The SCAN and READ alarms are called
by the record support routines. The Calculation alarm is called by the
record processing routine when the CALC expression is an invalid one, upon
which an error message is generated.

<P>&nbsp;The following alarm parameters which are configured by the user
define the limit alarms for the VAL field and the severity corresponding
to those conditions.

<P>&nbsp;The HYST field defines an alarm deadband for each limit. See the
EPICS Record Reference Manual for a complete explanation of alarms
and these fields. 

<P>
<TABLE BORDER>
<TR>
<TH>Field</TH>
<TH>Summary</TH>
<TH>Type</TH>
<TH>DCT</TH>
<TH>Initial</TH>
<TH>Access</TH>
<TH>Modify</TH>
<TH>Rec Proc Monitor</TH>
<TH>PP</TH>
</TR>

<TR>
<TD>HIHI</TD>
<TD>Hihi Alarm Limit</TD>
<TD>FLOAT</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>Yes</TD>
</TR>

<TR>
<TD>HIGH</TD>
<TD>High Alarm Limit</TD>
<TD>FLOAT</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>Yes</TD>
</TR>

<TR>
<TD>LOW</TD>
<TD>Low Alarm Limit</TD>
<TD>FLOAT</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>Yes</TD>
</TR>

<TR>
<TD>LOLO</TD>
<TD>Lolo Alarm Limit</TD>
<TD>FLOAT</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>Yes</TD>
</TR>

<TR>
<TD>HHSV</TD>
<TD>Severity for a Hihi Alarm</TD>
<TD>Menu</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>Yes</TD>
</TR>

<TR>
<TD>HSV</TD>
<TD>Severity for a High Alarm</TD>
<TD>Menu</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>Yes</TD>
</TR>

<TR>
<TD>LSV</TD>
<TD>Severity for a Low Alarm</TD>
<TD>Menu</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>Yes</TD>
</TR>

<TR>
<TD>LLSV</TD>
<TD>Severity for a Lolo Alarm</TD>
<TD>Menu</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>Yes</TD>
</TR>

<TR>
<TD>HYST</TD>
<TD>Alarm Deadband</TD>
<TD>DOUBLE</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

</TABLE>
&nbsp;

<HR>
<P><A NAME="HEADING14-126"></A>
<H1>
8. Monitor Parameters</H1>

These parameters are used to determine when to send monitors for the
value fields. The monitors are sent when the value field exceeds the last
monitored field by the appropriate deadband, the ADEL for archiver monitors
and the MDEL field for all other types of monitors. If these fields have
a value of zero, every time the value changes, monitors are triggered;
if they have a value of -1, every time the record is scanned, monitors
are triggered.

<TABLE BORDER >
<TR>
<TH>Field</TH>
<TH>Summary</TH>
<TH>Type</TH>
<TH>DCT</TH>
<TH>Initial</TH>
<TH>Access</TH>
<TH>Modify</TH>
<TH>Rec Proc Monitor</TH>
<TH>PP</TH>
</TR>

<TR>
<TD>ADEL</TD>
<TD>Archive Deadband</TD>
<TD>DOUBLE</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>MDEL</TD>
<TD>Monitor, i.e. value change, Deadband</TD>
<TD>DOUBLE</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

</TABLE>
&nbsp;

<HR>
<P><A NAME="HEADING14-128"></A>
<H1>
9. Run-time Parameters</H1>

These fields are not configurable using a configuration tool and none
are modifiable at run-time. They are used to process the record.

<P>&nbsp;The LALM field is used to implement the hysteresis factor for
the alarm limits.

<P>&nbsp;The LA-LL fields are used to decide when to trigger monitors for
the corresponding fields. For instance, if LA does not equal the value
for A, monitors for A are triggered. The MLST and MLST fields are used
in the same manner for the VAL field.

<P>
<TABLE BORDER>
<TR>
<TH>Field</TH>
<TH>Summary</TH>
<TH>Type</TH>
<TH>DCT</TH>
<TH>Initial</TH>
<TH>Access</TH>
<TH>Modify</TH>
<TH>Rec Proc Monitor</TH>
<TH>PP</TH>
</TR>

<TR>
<TD>LALM</TD>
<TD>Last Alarmed Value</TD>
<TD>DOUBLE</TD>
<TD>No</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>ALST</TD>
<TD>Archive Last Value</TD>
<TD>DOUBLE</TD>
<TD>No</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>MLST</TD>
<TD>Monitor Last Value</TD>
<TD>DOUBLE</TD>
<TD>No</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>LA</TD>
<TD>Previous Input Value for A</TD>
<TD>DOUBLE</TD>
<TD>No</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>LB</TD>
<TD>Previous Input Value for B</TD>
<TD>DOUBLE</TD>
<TD>No</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
</TR>

<TR>
<TD>LL</TD>
<TD>Previous Input Value for A</TD>
<TD>DOUBLE</TD>
<TD>No</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD> </TD>
<TD> </TD>
<TD> </TD>
<TD> </TD>
<TD> </TD>
<TD> </TD>
<TD> </TD>
<TD> </TD>
<TD> </TD>
</TR>

<TR>
<TD>LAA</TD>
<TD>Previous Input Value for AA</TD>
<TD>STRING[40]</TD>
<TD>No</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>LBB</TD>
<TD>Previous Input Value for BB</TD>
<TD>STRING[40]</TD>
<TD>No</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
</TR>

<TR>
<TD>LLL</TD>
<TD>Previous Input Value for LL</TD>
<TD>STRING[40]</TD>
<TD>No</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

</TABLE>
&nbsp;

<HR>
<P><A NAME="HEADING14-132"></A>
<H1>
10. Record Support Routines</H1>

<A NAME="HEADING14-133"></A>
<H3>
init_record</H3>
For each constant input link, the corresponding value field is initialized
with the constant value if the input link is CONSTANT or a channel access
link is created if the input link is PV_LINK.

<P>&nbsp;A routine postfix is called to convert the infix expression in
CALC and OCAL to reverse polish notation. The result is stored in RPCL
and ORPC, respectively.

<P>&nbsp;<A NAME="HEADING14-136"></A>
<H3>
process</H3>
See section 11.

<P>&nbsp;<A NAME="HEADING14-138"></A>
<H3>
special</H3>
This is called if CALC or OCAL is changed. special calls sCalcPostfix.

<P>&nbsp;<A NAME="HEADING14-140"></A>
<H3>
get_value</H3>
Fills in the values of struct valueDes so that they refer to VAL.

<P>&nbsp;<A NAME="HEADING14-142"></A>
<H3>
get_units</H3>
Retrieves EGU.

<P>&nbsp;<A NAME="HEADING14-144"></A>
<H3>
get_precision</H3>
Retrieves PREC.

<P>&nbsp;<A NAME="HEADING14-146"></A>
<H3>
get_graphic_double</H3>
Sets the upper display and lower display limits for a field. If the field
is VAL, HIHI, HIGH, LOW, or LOLO, the limits are set to HOPR and LOPR,
else if the field has upper and lower limits defined they will be used,
else the upper and lower maximum values for the field type will be used.

<P>&nbsp;<A NAME="HEADING14-148"></A>
<H3>
get_control_double</H3>
Sets the upper control and the lower control limits for a field. If the
field is VAL, HIHI, HIGH, LOW, or LOLO, the limits are set to HOPR and
LOPR, else if the field has upper and lower limits defined they will be
used, else the upper and lower maximum values for the field type will be
used.

<P>&nbsp;<A NAME="HEADING14-150"></A>
<H3>
get_alarm_double</H3>
Sets the following values:

<P>&nbsp;upper_alarm_limit = HIHI

<P>&nbsp;upper_warning_limit = HIGH

<P>&nbsp;lower_warning_limit = LOW

<P>&nbsp;lower_alarm_limit = LOLO

<HR>
<P>&nbsp;<A NAME="HEADING14-156"></A>
<H1>
11. Record Processing</H1>

<A NAME="HEADING14-157"></A>
<H2>
11.1. process()</H2>
The <TT>process()</TT> routine implements the following algorithm:

<P>&nbsp;
<DL>
<DD>
1. Fetch all arguments.</DD>


<P>&nbsp;
<DD>
2. Call routine sCalcPerform(), which calculates VAL from the postfix version
of the expression given in CALC. If sCalcPerform() returns success, UDF
is set to FALSE.</DD>


<P>&nbsp;
<DD>
3. Check alarms. This routine checks to see if the new VAL causes the alarm
status and severity to change. If so, NSEV, NSTA and LALM are set. It also
honors the alarm hysteresis factor (HYST). Thus the value must change by
at least HYST before the alarm status and severity changes.</DD>


<P>&nbsp;
<DD>
4. Determine if the Output Execution Option (OOPT) is met. If it is met,
either execute the output link (and output event) immediately (if ODLY
= 0), or schedule a callback to do so after the specified interval. See the
explanation for the <TT>execOutput()</TT> routine below.</DD>


<P>&nbsp;
<DD>
5. Check to see if monitors should be invoked.</DD>


<P>&nbsp;
<UL>
<LI>
Alarm monitors are invoked if the alarm status or severity has changed.</LI>


<P>&nbsp;
<LI>
Archive and value change monitors are invoked if ADEL and MDEL conditions
are met.</LI>


<P>&nbsp;
<LI>
Monitors for A-L and AA-LL are checked whenever other monitors are invoked.</LI>


<P>&nbsp;
<LI>
NSEV and NSTA are reset to 0.</LI>


<P>&nbsp;</UL>

<DD>
6. If no output delay was specified, scan forward link if necessary, set
PACT FALSE, and return.</DD>


<P>&nbsp;</DL>
<A NAME="HEADING14-169"></A>
<H2>
11.2. execOutput()</H2>

<DL>
<DD>
1. If DOPT field specifies the use of OCAL, call the routine sCalcPerform
for the postfix version of the expression in OCAL. Otherwise, use VAL.</DD>


<P>&nbsp;
<DD>
2. If the Alarm Severity is INVALID, follow the option as designated by
the field IVOA.</DD>


<P>&nbsp;
<DD>
3. If the Alarm Severity is not INVALID or IVOA specifies "Continue Normally",
call device support to write the value of OVAL to device or PV specified by
the OUT link, and post the event in OEVT (if non-zero).</DD>


<P>&nbsp;
<DD>
4. If an output delay was implemented, process the forward link.</DD>

</DL>
<P>&nbsp;

<A NAME="HEADING14-170"></A>
<H2>
12. Sample Database</H2>

Here's a sample database fragment that illustrates how to include a constant
literal string within a calc expression.  At run time, you could enter the
expression below either as

<pre>
AA+printf(' %.3f',A)
</pre>

or as

<pre>
AA+printf(" %.3f",A)
</pre>

But in a database, you don't have that freedom, because the entire expression
is the value of an EPICS field, which must be enclosed in double quotes:

<blockquote>
<pre>
record(scalcout, "$(P)SRS810:$(N):SetPhas") {
    field(DESC, "Create Phase Set Str")
    field(CALC, "AA+printf(' %.3f',A)")
    field(OUT, "$(P)SRS810:$(N):WritePhas.AOUT  PP MS")
    field(PREC, "2")
    field(AA, "PHAS")
}
</pre>
</blockquote>



</pre>

<P>

<HR>
<ADDRESS>Tim Mooney</ADDRESS>

</BODY>
</HTML>
